'''
在讲解装饰器之前先了解python的以下规则
    1.可以将函数存储在变量中
    2.可以将函数作为参数传给其他函数
    3.可以定义嵌套函数，即在函数中定义函数
    4.什么是闭包
        当一个函数内部定义了另一个函数，并且内部函数引用了外部函数的变量时，就创建了一个闭包。
        这个内部函数可以访问外部函数中的变量，即使外部函数已经执行完毕并返回，闭包仍然可以访问并修改这些变量。
可以参考：
    https://zhuanlan.zhihu.com/p/640193185
'''

# 示例1：将函数作为参数传递给另一函数


def get_message(message):
    return message


def call_func(func,message):
    print(func(message))


call_func(func=get_message,message='hello')

# 示例2：嵌套函数


def outer_func(outer_arg):
    def inner_func(inner_arg):
        print('arg:'+inner_arg)
    # 执行return后outer_func()的返回值为None
    return inner_func(outer_arg)


outer_func('hello innner')

# 示例3： 外部函数返回值为内部函数对象（闭包）


def outer_func2(arg):
    def inner_func(inner_arg):
        print('arg:'+inner_arg)
    # 执行return后outer_func()的返回值为函数对象inner_func,类型为<class 'function'>
    return inner_func


print(type(outer_func2('outer')))
result = outer_func2('outer2')
result('outer2')


'''
装饰器介绍：
    装饰器是一种特殊的函数，接受一个函数作为输入，并返回一个新的函数或者替换原来的函数。
    通过在函数定义的上方使用装饰器语法@装饰器名称，可以将装饰器应用于函数。
    装饰器可以在不修改原始函数代码的情况下，对函数进行一些额外的操作或修改。常见的装饰器用途包括：
        添加日志记录、性能分析或调试信息
        实现缓存功能，避免重复计算
        引入权限检查或用户认证
        修改函数的输入或输出
        修改函数的行为或逻辑
装饰器分类：
    函数装饰器
    类装饰器
装饰器语法糖 @的介绍：
    如果你接触Python有一段时间了的话，想必你对@符号一定不陌生了，没错@符号就是装饰器的语法糖。
    它放在一个函数开始定义的地方，它就像一顶帽子一样戴在这个函数的头上。和这个函数绑定在一起。
    在我们调用这个函数的时候，第一件事并不是执行这个函数，而是将这个函数做为参数传入它头顶上这顶帽子，
    这顶帽子我们称之为装饰函数或装饰器。

装饰器的定义与使用步骤：
    1.先定义一个装饰器函数，与普通函数的区别是，装饰器是一个嵌套函数，通常参数是函数对象，返回值是嵌套涵数的内部函数
    2.定义业务函数或者类
    3.最后将 @装饰函数 放置在业务函数定义前或者类定义前
'''

# 示例1：装饰不带参数的函数，即业务函数不带参数，非语法糖形式调用

# 装饰器函数
def decorator1(func):
    def wrapper():
        print('wrapper of decorator1')
        func()
    return wrapper

# 业务函数
def greet():
    print('greet func():hello word')
# 非语法糖形式调用
result_func1=decorator1(greet)
result_func1()

# 示例2：装饰带参数的函数，语法糖形式调用，等价于示例1
def decorator2(func):
    def wrapper():
        print('wrapper of decorator1')
        func()
    return wrapper

@decorator2
def greet2():
    print('greet2 func():hello word')

greet2()

# 示例3： 装饰带参数的函数,即业务函数带参数
def decorator3(func):
    def wrapper(message):
        print('wrapper of decorator3 message='+message)
        func(message)
    return wrapper

@decorator3
def greet3(message):
    print('greet3 func():'+message)

greet3('zxp')
# 示例4：装饰器带参数
def repeat(num):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(num):
                print('wrapper of decorator')
                func(*args, **kwargs)
        return wrapper
    return my_decorator

@repeat(4)
def greet4(message):
    print('greet4 func():'+message)

# @语法糖等价于：
# my_decorator = repeat(4)
# greet4 = my_decorator(greet4)

greet4('zxp')


